﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace com.ptrampert.ObjectContexts
{
    /// <summary>
    /// Provides a basic ObjectContext interface.
    /// </summary>
    public interface IObjectContext : IDisposable
    {
        /// <summary>
        /// Gets whether or not the context has been disposed.
        /// </summary>
        bool Disposed { get; }

        /// <summary>
        /// Get all objects of type T.
        /// </summary>
        /// <typeparam name="T">Type of object to get.</typeparam>
        /// <returns>All objects of type T.</returns>
        IQueryable<T> All<T>() where T : class;

        /// <summary>
        /// Find the object of type T identified by ids.
        /// </summary>
        /// <typeparam name="T">Type of object.</typeparam>
        /// <param name="ids">Object's identifiers.</param>
        /// <returns>Object identified by ids, or null if not found.</returns>
        T Find<T>(params object[] ids) where T : class;

        /// <summary>
        /// Find all objects of type T matching predicate.
        /// </summary>
        /// <typeparam name="T">Type of object to search for.</typeparam>
        /// <param name="predicate">Conditions for matching objects.</param>
        /// <returns>All matching objects.</returns>
        IQueryable<T> Find<T>(Expression<Func<T, bool>> predicate) where T : class;

        /// <summary>
        /// Update an object of type T.
        /// </summary>
        /// <typeparam name="T">Type of object being updated.</typeparam>
        /// <param name="obj">The object to update.</param>
        void Update<T>(T obj) where T : class;

        /// <summary>
        /// Add an object of type T.
        /// </summary>
        /// <typeparam name="T">Type of object being added.</typeparam>
        /// <param name="obj">The object being added.</param>
        void Add<T>(T obj) where T : class;

        /// <summary>
        /// Delete an object of type T.
        /// </summary>
        /// <typeparam name="T">Type of object being deleted.</typeparam>
        /// <param name="obj">The object being deleted.</param>
        void Delete<T>(T obj) where T : class;

        /// <summary>
        /// Delete an object of type T identified by ids.
        /// </summary>
        /// <typeparam name="T">Type of object to delete.</typeparam>
        /// <param name="ids">Identifier for the object.</param>
        void Delete<T>(params object[] ids) where T : class;

        /// <summary>
        /// Delete all object matching the given predicate.
        /// </summary>
        /// <typeparam name="T">Type of object to delete.</typeparam>
        /// <param name="predicate">Condition for deletion.</param>
        void Delete<T>(Expression<Func<T, bool>> predicate) where T : class;

        /// <summary>
        /// Commit changes.
        /// </summary>
        void Commit();

        /// <summary>
        /// Get all objects of type T.
        /// </summary>
        /// <typeparam name="T">Type of object to get.</typeparam>
        /// <returns>All objects of type T.</returns>
        Task<IQueryable<T>> AllAsync<T>() where T : class;

        /// <summary>
        /// Find the object of type T identified by ids.
        /// </summary>
        /// <typeparam name="T">Type of object.</typeparam>
        /// <param name="ids">Object's identifiers.</param>
        /// <returns>Object identified by ids, or null if not found.</returns>
        Task<T> FindAsync<T>(params object[] ids) where T : class;

        /// <summary>
        /// Find all objects of type T matching predicate.
        /// </summary>
        /// <typeparam name="T">Type of object to search for.</typeparam>
        /// <param name="predicate">Conditions for matching objects.</param>
        /// <returns>All matching objects.</returns>
        Task<IQueryable<T>> FindAsync<T>(Expression<Func<T, bool>> predicate) where T : class;

        /// <summary>
        /// Update an object of type T.
        /// </summary>
        /// <typeparam name="T">Type of object being updated.</typeparam>
        /// <param name="obj">The object to update.</param>
        Task UpdateAsync<T>(T obj) where T : class;

        /// <summary>
        /// Add an object of type T.
        /// </summary>
        /// <typeparam name="T">Type of object being added.</typeparam>
        /// <param name="obj">The object being added.</param>
        Task AddAsync<T>(T obj) where T : class;

        /// <summary>
        /// Delete an object of type T.
        /// </summary>
        /// <typeparam name="T">Type of object being deleted.</typeparam>
        /// <param name="obj">The object being deleted.</param>
        Task DeleteAsync<T>(T obj) where T : class;

        /// <summary>
        /// Delete an object of type T identified by ids.
        /// </summary>
        /// <typeparam name="T">Type of object to delete.</typeparam>
        /// <param name="ids">Identifier for the object.</param>
        Task DeleteAsync<T>(params object[] ids) where T : class;

        /// <summary>
        /// Delete all object matching the given predicate.
        /// </summary>
        /// <typeparam name="T">Type of object to delete.</typeparam>
        /// <param name="predicate">Condition for deletion.</param>
        Task DeleteAsync<T>(Expression<Func<T, bool>> predicate) where T : class;

        /// <summary>
        /// Commit changes.
        /// </summary>
        Task CommitAsync();
    }
}
